package com.sx.mvvmlibs.http.tools;


import android.util.Base64;

import org.jetbrains.annotations.NotNull;

import java.nio.charset.StandardCharsets;
import java.security.SecureRandom;
import java.util.Random;

import javax.crypto.Cipher;
import javax.crypto.spec.SecretKeySpec;

/**
 * @Author: YY
 * @Date: 2021/4/7
 * @Description: AES加密工具类
 */
public class AESUtils {

    /**
     * 算法/模式/补码方式
     */
    private static final String CIPHER_MODE = "AES/ECB/PKCS5Padding";

    /**
     * AES秘钥支持128bit/192bit/256bit三种长度的秘钥，一个字节等于8bit，
     * 因此支持生成的字符串的长度应该是 16/24/32
     */
    private static final int kEY_LENGTH = 16;

    /**
     * @param length 需要生成的字符串长度
     * @return 随机生成的字符串
     */
    public static String getRandomKey(int length) {

        if (length != 16 && length  != 24 && length != 32) {
            System.out.println("长度必须为16/24/32");
            return null;
        }

        String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
        Random random = new Random();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < length; i++) {
            int number = random.nextInt(62);
            stringBuilder.append(str.charAt(number));
        }
        return stringBuilder.toString();
    }

    public static String getKey() {
        StringBuilder uid = new StringBuilder();
        // 产生16位的强随机数
        Random random = new SecureRandom();
        for (int i = 0; i < kEY_LENGTH; i++) {
            // 产生0-2的3位随机数
            int type = random.nextInt(3);
            switch (type) {
                case 0:
                    // 0-9的随机数
                    uid.append(random.nextInt(10));
                    break;
                case 1:
                    // ASCII在65-90之间为大写，获取大写随机
                    uid.append((char) (random.nextInt(25) + 65));
                    break;
                case 2:
                    // ASCII在97-122之间为小写，获取小写随机
                    uid.append((char) (random.nextInt(25) + 97));
                    break;
                default:
                    break;
            }
        }
        return uid.toString();
    }


    /**
     * @param data 需要加密的数据
     * @param key  加密使用的key
     * @return 加密后的数据(Base64编码)
     * @throws Exception
     */
    public static String encrypt(String data, @NotNull String key) throws Exception {
        int length = key.length();
        if (length != 16 && length != 24 && length != 32) {
            System.out.println("长度必须为16/24/32");
            return null;
        }

        byte[] raw = key.getBytes(StandardCharsets.UTF_8);
        SecretKeySpec keySpec = new SecretKeySpec(raw, "AES");
        Cipher cipher = Cipher.getInstance(CIPHER_MODE);
        cipher.init(Cipher.ENCRYPT_MODE, keySpec);
        byte[] encrypted = cipher.doFinal(data.getBytes(StandardCharsets.UTF_8));

        return Base64.encodeToString(encrypted, Base64.NO_WRAP);
    }


    /**
     * @param data 需要解密的数据
     * @param key  解密用的key
     * @return 解密后的数据
     * @throws Exception
     */
    public static String decrypt(String data, @NotNull String key) throws Exception {
        try {
            String resultKey = key.substring(key.length() -16);
            int length = resultKey.length();
            if (length != 16 && length != 24 && length != 32) {
                System.out.println("长度必须为16/24/32");
                return null;
            }

            byte[] raw = resultKey.getBytes(StandardCharsets.UTF_8);
            SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");
            Cipher cipher = Cipher.getInstance(CIPHER_MODE);
            cipher.init(Cipher.DECRYPT_MODE, skeySpec);
            //先用base64解密
            byte[] encrypted = Base64.decode(data, Base64.NO_WRAP);
            try {
                byte[] original = cipher.doFinal(encrypted);
                return new String(original, StandardCharsets.UTF_8);
            } catch (Exception e) {
                System.out.println(e.toString());
                return null;
            }
        } catch (Exception ex) {
            System.out.println(ex.toString());
            return null;
        }
    }
}
